using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.IO;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace Woz
{
    /// <summary>
    /// the resource manager manages the all of the resources
    /// </summary>
    public sealed class ResourceManager
    {
        /// <summary>
        /// private default constructor of resource manager
        /// </summary>
        private ResourceManager()
        {
            // instantiate the images dictionary
            this.mImages = new Dictionary<string, Image>();

            // instantiate the cursors dictionary
            this.mCursors = new Dictionary<string, Cursor>();

            // add a few cursors
            this.mCursors["hand"] = System.Windows.Forms.Cursors.Hand;
            this.mCursors["arrow"] = System.Windows.Forms.Cursors.Arrow;
            this.mCursors["cross"] = System.Windows.Forms.Cursors.Cross;
            this.mCursors["sizeall"] = System.Windows.Forms.Cursors.SizeAll;
            this.mCursors["sizenesw"] = System.Windows.Forms.Cursors.SizeNESW;
            this.mCursors["sizenwse"] = System.Windows.Forms.Cursors.SizeNWSE;
            this.mCursors["invalid"] = System.Windows.Forms.Cursors.No;
            
            // create empty cursor
            using (Bitmap bmp = new Bitmap(16, 16))
            {
                using (Graphics gfx = Graphics.FromImage(bmp))
                {
                    gfx.Clear(Color.FromArgb(0, Color.White));
                }
                this.AddCursor("none", bmp);
            }

            // create the pens list
            this.mPens = new List<Pen>();

            // create the microsoft ink object
            this.mInk = new Microsoft.Ink.Ink();
        }

        /// <summary>
        /// get the single instance of the resource manager
        /// </summary>
        public static ResourceManager Instance
        {
            get
            {
                // if the instance is not already loaded
                if (sInstance == null)
                {
                    // delay load the instance of the resource manager
                    sInstance = new ResourceManager();
                }

                // return the single instance of the resource manager
                return sInstance;
            }
        }

        /// <summary>
        /// dictionary of loaded images
        /// </summary>
        public Dictionary<string, Image> Images
        {
            get
            {
                return this.mImages;
            }
        }

        /// <summary>
        /// dictionary of cursors
        /// </summary>
        public Dictionary<string, Cursor> Cursors
        {
            get
            {
                return this.mCursors;
            }
        }

        /// <summary>
        /// the shared ink object
        /// </summary>
        public Microsoft.Ink.Ink Ink
        {
            get
            {
                return this.mInk;
            }
        }

        /// <summary>
        /// gets or sets the open file dialog function
        /// </summary>
        public OpenFileDialogHandler OpenFileDialogMethod
        {
            get
            {
                return this.mOpenFileDialogMethod;
            }
            set
            {
                this.mOpenFileDialogMethod = value;
            }
        }

        /// <summary>
        /// gets or sets the save file dialog function
        /// </summary>
        public SaveFileDialogHandler SaveFileDialogMethod
        {
            get
            {
                return this.mSaveFileDialogMethod;
            }
            set
            {
                this.mSaveFileDialogMethod = value;
            }
        }

        /// <summary>
        /// gets or sets the color dialog function
        /// </summary>
        public ColorDialogHandler ColorDialogMethod
        {
            get
            {
                return this.mColorDialogMethod;
            }
            set
            {
                this.mColorDialogMethod = value;
            }
        }

        /// <summary>
        /// gets or sets the set status text function
        /// </summary>
        public SetStatusTextHandler SetStatusTextMethod
        {
            get
            {
                return this.mSetStatusTextMethod;
            }
            set
            {
                this.mSetStatusTextMethod = value;
            }
        }

        /// <summary>
        /// gets or sets the progress start function
        /// </summary>
        public ProgressStartHandler ProgressStartMethod
        {
            get
            {
                return this.mProgressStartMethod;
            }
            set
            {
                this.mProgressStartMethod = value;
            }
        }

        /// <summary>
        /// gets or sets the progress update function
        /// </summary>
        public ProgressUpdateHandler ProgressUpdateMethod
        {
            get
            {
                return this.mProgressUpdateMethod;
            }
            set
            {
                this.mProgressUpdateMethod = value;
            }
        }

        /// <summary>
        /// gets or sets the progress end function
        /// </summary>
        public ProgressEndHandler ProgressEndMethod
        {
            get
            {
                return this.mProgressEndMethod;
            }
            set
            {
                this.mProgressEndMethod = value;
            }
        }

        /// <summary>
        /// initialize the resource manager
        /// </summary>
        /// <returns>true if the resource manager initializes false otherwise</returns>
        public bool Initialize()
        {
            // call the load images routine
            if (!this.LoadImages())
            {
                return false;
            }

            return true;
        }

        /// <summary>
        /// load all of the system images
        /// </summary>
        /// <returns>true if all the images are loaded false otherwise</returns>
        private bool LoadImages()
        {
            // get all the filenames in this directory
            string[] imageFileNames = Directory.GetFiles(Path.Combine(Woz.StaticVariables.Instance.MediaFolder, "images/"));

            // loop through each of the image files and create images and add them to our dictionary
            foreach (string imageFileName in imageFileNames)
            {
                // ignore the thumbs db file that may pop up
                if (imageFileName.EndsWith(".db"))
                {
                    continue;
                }

                // create an image and add it to our dictionary
                this.mImages[Path.GetFileName(imageFileName)] = Image.FromFile(imageFileName);
            }

            // send back a successful messege
            return true;
        }

        /// <summary>
        /// gets a pen with the specified color and thickness
        /// </summary>
        /// <param name="pColor">the color of the pen</param>
        /// <param name="pWidth">the thickness of the pen</param>
        /// <returns>the pen with the given settings</returns>
        public Pen GetPen(Color pColor, float pWidth)
        {
            // loop through all the pens in our list and see if we can find this pen
            foreach (Pen pen in this.mPens)
            {
                // check if both the pen color and width are the same
                if ((pen.Color == pColor) && (pen.Width == pWidth))
                {
                    // omg we have this pen so lets send it back
                    return pen;
                }
            }

            // if we made it this far then this pen doesnt exist so create it
            Pen newPen = new Pen(pColor, pWidth);

            // set the dash cap on this new pen
            newPen.DashCap = DashCap.Round;

            // set the end cap on this new pen
            newPen.EndCap = LineCap.Round;

            // set the start cap on this new pen
            newPen.StartCap = LineCap.Round;

            // save this pen into the dictionary
            this.mPens.Add(newPen);

            // send back the new pen
            return newPen;
        }

        /// <summary>
        /// adds a cursor to the cursor dictionary
        /// </summary>
        /// <param name="pCursorName">the name of this new cursor</param>
        /// <param name="pCursorImage">an image containing the cursor</param>
        public void AddCursor(string pCursorName, Bitmap pCursorImage)
        {
            // ignore if this cursor exists
            if (this.mCursors.ContainsKey(pCursorName))
            {
                return;
            }

            // add it to the dictionary
            this.mCursors[pCursorName] = new Cursor(pCursorImage.GetHicon());
        }

        /// <summary>
        /// adds a cursor to the cursor dictionary
        /// </summary>
        /// <param name="pCursorName">the name of this new cursor</param>
        /// <param name="pCursorImage">an image containing the cursor</param>
        public void AddCursor(string pCursorName, Image pCursorImage)
        {
            this.AddCursor(pCursorName, new Bitmap(pCursorImage));
        }

        #region OpenFileDialog / SaveFileDialog / ColorDialog
        public class FileDialogArgs : EventArgs
        {
            public bool AddExtension = true;
            public bool CheckFileExists = true;
            public bool CheckPathExists = true;
            public string DefaultExt = "";
            public bool DereferenceLinks = true;
            public string FileName = "";
            public string[] FileNames;
            public string Filter = "";
            public int FilterIndex = 1;
            public string InitialDirectory = "";
            public bool RestoreDirectory = false;
            public bool ShowHelp = false;
            public bool SupportMultiDottedExtensions = false;
            public string Title = "";
            public bool ValidateNames = true;
            public DialogResult DialogResult = DialogResult.None;

            public FileDialogArgs(string pTitle, string pFilterList, int pFilterIndex)
            {
                this.Title = pTitle;
                this.Filter = pFilterList;
                this.FilterIndex = pFilterIndex;
            }

            public FileDialogArgs(string pTitle, string pFilterList, int pFilterIndex, string pInitialDirectory)
            {
                this.Title = pTitle;
                this.Filter = pFilterList;
                this.FilterIndex = pFilterIndex;
                this.InitialDirectory = pInitialDirectory;
            }
        }
        public class OpenFileDialogArgs : FileDialogArgs
        {
            public bool Multiselect = false;
            public bool ReadOnlyChecked = false;
            public bool ShowReadOnly = false;

            public OpenFileDialogArgs(string pTitle, string pFilterList, int pFilterIndex)
                : base(pTitle, pFilterList, pFilterIndex)
            {
            }

            public OpenFileDialogArgs(string pTitle, string pFilterList, int pFilterIndex, string pInitialDirectory)
                : base(pTitle, pFilterList, pFilterIndex, pInitialDirectory)
            {
            }
        }
        public class SaveFileDialogArgs : FileDialogArgs
        {
            public bool CreatePrompt = false;
            public bool OverridePrompt = false;

            public SaveFileDialogArgs(string pTitle, string pFilterList, int pFilterIndex)
                : base(pTitle, pFilterList, pFilterIndex)
            {
            }

            public SaveFileDialogArgs(string pTitle, string pFilterList, int pFilterIndex, string pInitialDirectory)
                : base(pTitle, pFilterList, pFilterIndex, pInitialDirectory)
            {
            }
        }
        public delegate void FileDialogHandler(object sender, FileDialogArgs e);
        public delegate void OpenFileDialogHandler(object sender, OpenFileDialogArgs e);
        public delegate void SaveFileDialogHandler(object sender, SaveFileDialogArgs e);

        public class ColorDialogArgs : EventArgs
        {
            public DialogResult DialogResult = DialogResult.None;
            public bool AllowFullOpen = true;
            public bool AnyColor = true;
            public Color Color = Color.Black;
            public int[] CustomColors;
            public bool FullOpen = false;
            public bool SolidColorOnly = false;
        }
        public delegate void ColorDialogHandler(object pSender, ColorDialogArgs pArgs);
        #endregion

        #region Progress Bar / Status Text
        public delegate void SetStatusTextHandler(string pText, int pDuration);
        public delegate void ProgressStartHandler(string pText, EventHandler pMethod);
        public delegate void ProgressUpdateHandler(int pPercent);
        public delegate void ProgressEndHandler(int pDuration);
        #endregion

        /// <summary>
        /// the static instance of this singleton class
        /// </summary>
        private static ResourceManager sInstance;

        /// <summary>
        /// the pens well use to draw the strokes
        /// </summary>
        private List<Pen> mPens;

        /// <summary>
        /// the microsoft ink object
        /// </summary>
        private Microsoft.Ink.Ink mInk;

        /// <summary>
        /// the list of images
        /// </summary>
        private readonly Dictionary<string, Image> mImages;

        /// <summary>
        /// the list of cursors
        /// </summary>
        private readonly Dictionary<string, Cursor> mCursors;

        /// <summary>
        /// a save file dialog that will be set from the client
        /// </summary>
        private SaveFileDialogHandler mSaveFileDialogMethod;

        /// <summary>
        /// an open file dialog that will be set from the client
        /// </summary>
        private OpenFileDialogHandler mOpenFileDialogMethod;

        /// <summary>
        /// a color dialog that will be set from the client
        /// </summary>
        private ColorDialogHandler mColorDialogMethod;

        /// <summary>
        /// sets the status text of the client for a certain amount of time
        /// </summary>
        private SetStatusTextHandler mSetStatusTextMethod;

        /// <summary>
        /// starts the progress bar on the client
        /// </summary>
        private ProgressStartHandler mProgressStartMethod;

        /// <summary>
        /// updates the progress bar on the client
        /// </summary>
        private ProgressUpdateHandler mProgressUpdateMethod;

        /// <summary>
        /// finishes the progress bar on the client
        /// </summary>
        private ProgressEndHandler mProgressEndMethod;
    }
}
